﻿/**
 * Nutilities
 * 
 * Package: Net
 */

using System.IO;
using System.Net.Sockets;
using System.Threading;

namespace Nutilities.Net
{
    /// <summary>
    /// A socket implementation, in which the input stream reading is threaded
    /// </summary>
    public abstract class ThreadedSocket
    {
        public bool Connected
        {
            get { return Socket.Connected; }
        }

        public Socket Socket { get; private set; }
        public BinaryWriter Writer { get; private set; }
        public BinaryReader Reader { get; private set; }

        protected bool Running { get; set; }
        protected Thread _thread;

        public string Name { get; set; }

        protected ThreadedSocket(Socket socket)
        {
            Socket = socket;
            var ns = new NetworkStream(socket);
            Writer = new BinaryWriter(ns);
            Reader = new BinaryReader(ns);
        }

        public void Start()
        {
            Running = true;
            _thread = new Thread(Run) {Name = Name};
            _thread.Start();
        }

        /// <summary>
        /// Closes the socket, kills the thread and then waits for the thread to terminate
        /// </summary>
        public void Stop()
        {
            if (_thread == null) return;
            Running = false;
            Close();
            _thread.Join();
        }

        /// <summary>
        /// Closes the socket and kills the thread
        /// </summary>
        protected void Terminate()
        {
            if (_thread == null) return;
            Running = false;
            Close();
        }

        public void Close()
        {
            Writer.Close();
            Reader.Close();
            Socket.Close();
        }

        private void Run()
        {
            try
            {
                while (Running)
                {
                    byte message = Reader.ReadByte();
                    MessageReceived(message);
                }
            }
            catch (IOException)
            {
                
            }
        }

        /// <summary>
        /// Called whenever a new message (1 byte) is read from the input stream
        /// </summary>
        /// <param name="message">The message read from the stream</param>
        protected abstract void MessageReceived(byte message);
    }
}
